﻿/*本章内容包括：
·C++内置的整型—unsigned long、long、unsigned int、int、unsigned short、short、char、unsigned char、signed char和bool。
   ·C++11新增的整型：unsigned long long和long long。
   ·表示各种整型的系统限制的 c_limits 文件。
   · 各种整型的数字字面值（常量）。
   · 使用 const 限定符来创建符号常量。
   · C++内置的浮点类型：float、double 和 long double。
   · 表示各种浮点类型的系统限制的 c_float 文件。
   ·C++变量的命名规则。
   · 各种浮点类型的数字字面值。
   · C++的算术运算符。
   · 自动类型转换。
   · 强制类型转换。*/
#include "Chapter3_ClassType.h"
#include <iostream>
#include <map>
#include <climits>
#include <fstream>
#include <iomanip>
#include <iso646.h>

//编译过程中匠源代码传递给预处理器，告诉处理器，在程序中查找替换，c语言遗留C++中会用const。第四章讨论
//#define INT_MAX 32767
#define ZERO 0
using std::cout;
using std::cin;
using std::string;
using std::map;
using std::dec;//十进制
using std::hex;//十六进制
using std::oct;//八进制


void Chapter3_ClassType::countType()
{   string nNameType ="int";
    string sNameType ="short";
    string lNameType ="long";
    string  llNameType ="long long";
    string fNameType ="float";
    string dNameType ="double";
    map<std::string, int> myMap;
    // 向map中添加一些元素
    myMap[nNameType] = 8;
    myMap[sNameType] = 8;
    myMap[lNameType] = 16;
    myMap[llNameType] = 32;
    myMap[fNameType] = 32;
    myMap[dNameType] = 64;
    for (const auto& pair : myMap) {
        cout << pair.first << ": " << pair.second << "位" <<'\n';
    }
    string find_key="double";
    auto it = myMap.find(find_key);
    // 检查迭代器是否指向map的末尾（即key不存在）
    /*if (it != myMap.end()) {
        cout << "The value for key "<<find_key<<" is : " << it->second << '\n';
    } else {
        cout << "Key "<<find_key<<" not found in the map." << '\n';
    }*/
    //siezof();返回字符类型长度
    
    std::cout << "Size of int: " << sizeof(int) << " bytes" << '\n';
    std::cout << "Size of int: " << sizeof(short) << " bytes" << '\n';
    std::cout << "Size of int: " << sizeof(long) << " bytes" << '\n';
    std::cout << "Size of int: " << sizeof(long long) << " bytes" << '\n';
    std::cout << "Size of int: " << sizeof(float) << " bytes" << '\n';
    std::cout << "Size of int: " << sizeof(double) << " bytes" << '\n';
    
}
//不同进制的写法定义，和cout输出不同进制,
void Chapter3_ClassType::test_unsigned_dechexoct()
{
    int rock= {1};
    cout << "可以使用{}初始化任何数据类型int rock= {1}:"<<rock<< '\n';
    short sam;
    unsigned short sue;
    sam =ZERO;
    sue = ZERO;
    cout << sam << '\n';
    cout << sue<< '\n';
    sam = 042;//042 八进制 0x42 十六进制42 十进制,存储到计算机都是2进制
    sue= sue-1;//典型的正数溢出行为，无符号整数0-1，变成最大
    cout << sam <<'\n';
    cout << sue<< '\n';
    cout <<"sam 默认的进制:"<< sam << '\n';
    cout << dec;//cont显示方式十进制
    cout <<"sam 十进制方式:"<< sam << '\n';
    cout <<hex;//cont显示方式十六进制
    cout <<"sam 十六进制方式:"<< sam << '\n';
    cout <<oct;//cont显示方式八进制
    cout <<"sam 八进制方式:"<< sam << '\n';
    cout <<hex;
    cout <<"除非有小数，或者值太大,否则默认int,末尾LU表示long unsigned,十六进制通常表示为内存地址 0x9c40(40000) : "<<40000<<'\n';
}

//导入老的climits 库，可以打印数据类型的最大值
void Chapter3_ClassType::climits_type()
{
    int n_int = INT_MAX;
    int n_short= SHRT_MAX;
    long n_long= LONG_MAX;
    long long n_llong= LLONG_MAX;
    float n_float= FLT_MAX;
    double n_double= DBL_MAX;
    cout << "INT_MAX : "<< n_int << '\n';
    cout << "SHRT_MAX : "<<n_short << '\n';
    cout << "LONG_MAX : "<<n_long << '\n';
    cout << "LLONG_MAX : "<<n_llong << '\n';
    cout << "FLT_MAX : "<<n_float << '\n';
    cout << "DBL_MAX : "<<n_double << '\n';
    cout << "Minimum int value : "<< INT_MIN << '\n';
    cout << "Bits per byte : "<< CHAR_BIT<<'\n';
    //c++11，可以使用大括号初始化任何数据类型。是一种常用的习惯
}

//char
void Chapter3_ClassType::test_char()
{   //'M'表示ASCII的数值编码
    char CHAR= 'A';
    int i = CHAR+1;
    cout << "CHAR : "<<CHAR<< '\n';
    cout << "i : "<<i<< '\n';
    cout<<"cout.put(i):";
    cout.put(static_cast<char>(i))<<'\n';//put()显示字符的方法，可代替<<
    cout<<"'!':";
    cout.put('!')<<'\n';
    cout<<"66:";
    cout.put(66)<<'\n';
    
    //'\a'报警，响铃符
    //cout.put('\a')<<'\n';
    //"\n"; 和‘/n’都是换行
    std::cout << "第一行\n";  // 使用字符串字面量
    std::cout << "第二行" << '\n';  // 使用字符字面量

    //可用八进制和十六进制 转义序列来表示字符.这两行代码都会输出ASCII码值为26的字符，然后输出一个换行符。大多数现代控制台和终端会将这个字符显示为一个不可见的符号
    cout<<'\032'<<'\n';
    cout.put(26)<<'\n';
    cout<<'\x1a'<<'\n';
    //输入密码:有铃音
    cout<<"\aOperation \"HyperHype\" is now activated! \n";
    cout<<"code:_____\b\b\b\b\b\b";
    long code;
    cin>>code;
    cout <<"\aYou entered"<< code << "...\n";
    
}

//通用字符名称.一种表示特殊字符的机制,独立于任何特定键盘
void Chapter3_ClassType::universalCharacterName(){
    
    cout<<"通用字符"<<'\n';
    
    //可以用\U(十六进制)或者\u(八进制)开头
    //这些字符表示是字符的ISO 10646码点，\u00E2显示 â
    //ASCII 码为Unicode的子集
    cout<<"Let them eat g\u00E2teau.\n";
    
    unsigned char c= '2';
    signed char c1= -1;//-128~127,直接输出是乱码,要转换
    cout<< c<<'\n';
    cout<< c1<<'\n';
    cout<< static_cast<int>(c1) <<'\n';
}

//宽字符类型，输出看做char流，宽字符集通常用于utf-16编码。wchar_t的大小至少足以容乃16位。
void Chapter3_ClassType::test_wcha_t()
{
    wchar_t wcha= L'A';
    std::wcout << wcha << '\n';
    // 创建一个宽字符字符串

    // 设置全局locale为系统默认
    std::locale::global(std::locale(""));

    wchar_t wc_str[] = L"こんにちは hahaha 我不知道这句话什么意思";
    // 使用 wprintf 来输出宽字符字符串
    wprintf(L"%ls\n", wc_str);
    // 输出宽字符字符串
    std::wcout << L"こんにちは" << '\n';
   
    wchar_t wc = L'に';
    char c[]= u8"に";
    //无符号的char16_t和char32_t  
    char16_t c16= U'q';
    char16_t c32= U'\U0000222b';
    std::wcout << wc <<'\n';
    std::wcout << "char c='に' :"<<c<<'\n';
    std::wcout << "char16_t c16:"<<c16<<'\n';
    std::wcout << "char32_t c32:"<<c32<<'\n';

    // 使用UTF-8编码的字符串
    std::string chinese = "汉字";
    std::string japanese = "こんにちは";
    // 输出字符串
    std::cout << chinese << '\n';
    std::cout << japanese << '\n';
    
}

//const初始化后,就不能改变.只读
//std::fixed 和 std::setprecision 是流操纵器(更推荐,更常用)，它们通常用于格式化输出，而 setf() 是一个成员函数，它提供了更细粒度的控制
void Chapter3_ClassType::test_const_double()
{
    const float million= 1.0e6;
    double d=12.5e1;
    double d1=12.5e-1;
    cout<<d<<'\n';
    cout<<d1<<'\n';
    double ten= 3.333;
    //使用setf setw 右对齐输出
    string prefixA = "ten million :";
    int  prefixlen= static_cast<int>(prefixA.length());
    //如果有字符串,需要宽度-字符串长度
    //使用流方式对齐
    cout<<"ten million :"<< std::fixed << std::setprecision(6)<<std::right<< std::setw(40-prefixlen)<<million*ten<<'\n';
    std::cout.setf(std::ios::fixed); // 设置浮点数以固定小数点形式显示
    std::cout.precision(1); // 设置浮点数的精度为6位小数
    //使用setf()函数对齐
    std::cout.setf(std::ios::right);
    cout<<std::setw(40)<<333333.0<<'\n';
    
    /*double value = 123.456789;
    // 左对齐，宽度为10，小数点后保留3位
    std::cout << std::left << std::setw(10) << std::setprecision(3) << value << std::endl;

    // 右对齐，宽度为10，小数点后保留3位
    std::cout << std::right << std::setw(10) << std::setprecision(3) << value << std::endl;

    // 内部对齐，宽度为10，小数点后保留3位
    std::cout << std::internal << std::setw(10) << std::setprecision(3) << value << std::endl;

    // 固定小数点，小数点后保留3位
    std::cout << std::fixed << std::setprecision(3) << value << std::endl;

    // 科学记数法，小数点后保留3位
    std::cout << std::scientific << std::setprecision(3) << value << std::endl;*/
}
//float 只保留6~7位，八位的时候会丢失尾数精度
void Chapter3_ClassType::test_float()
{
    using namespace std;
    //有f后缀 是float类型，没有f 会被解释称double，
    float a=2.34E+7f;
    cout<<a<<'\n';
    float b=a+1.0f;
    //float类型只能表示数字的前六位或者前七位，多余的就丢失了
    cout<<b-a<<'\n';
    /*//使用setf()函数或者fixed，设定格式，float运算都会丢失位数,因为位数不够。
    //ios_base::fixed 是你想要设置的格式标志。ios_base::floatfield 是你想要清除的格式标志字段。
    std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
    //cout.precision(6);如果不设置fixed 默认float是6位就是6.
    //cout<<fixed<<setprecision();
    float i,j;
    cout<<"i:";
    cin>>i;
    cout<<"j:";
    cin>>j;
    cout<<"i:"<<i<<'\n';
    cout<<"j:"<<j<<'\n';
    cout<<"i+j=";
    cout<<i+j<<'\n';*/
    std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
    cout<<"double constants: 1E7/9.0 = "<<1E7/9.0<<'\n';
    cout<<"float constants: 1E7/9.0f = "<<1E7f/9.0f<<'\n';
}
void Chapter3_ClassType::test_long_double()
{   //double 只保留14~15位，十六位的时候会丢失尾数精度
    //有f后缀 是float类型，没有f 会被解释称double，
    double a=2.34E+16;
    cout<<a<<'\n';
    double b=a+1.0;
    //float类型只能表示数字的前六位或者前七位，多余的就丢失了
    cout<<b-a<<'\n';
    
    /*unsigned long long a = static_cast<unsigned long long>(2.34E+22);
    cout << a << '\n';
    // 直接加上1.0 会被认为是double类型，进行隐形类型转化，double会丢失精度。这里写1 可以正确输出
    //unsigned long long  b = a + 1;
    unsigned long long  b = a + 1.0;
    //unsigned long long c = 1.0;
    //unsigned long long  b = a + c;
    // 输出字段宽度设置为20
    cout << std::setw(20) << b - a << '\n'; */
}
//类型转换，隐士类型装换，显示类型转换
//隐式转化可以是自动的，也可以是char 加int ASCII码转化，
//显式转化static_cast这种。安全性不如隐式
void Chapter3_ClassType::test_castType()
{
    int bats,coots;
    //int auks;
    //auks = 19.99+11.99;
    bats=(int) 19.99+ (int) 11.9;//old c
    coots=int(19.99)+int (11.9);// new C++ syntax
   // cout<<"auks = "<<auks<<'\n';
    cout<<"bats = "<<bats<<'\n';
    cout<<"coots = "<<coots<<'\n';
    char ch='Z';
    cout<<"The code for"<<ch<<'\n';
    cout<<int(ch)<<'\n';
    cout<<"yes,the code is"<< static_cast<int>(ch)<<'\n';
}
//auto,是C++中的关键字，c++11以后变得很常用.可以考虑用来定义变量,编译器将变量设置成与初始值相同
//auto 的使用是广泛且被推荐的如lanm表达式,和for循环，但也要注意不要过度使用，以免降低代码的可读性。
void Chapter3_ClassType::test_auto()
{
    auto n = 100;
    auto x = 1.5;
    auto y = 1.3e12L;
    cout<<n<<'\n';
    cout<<x<<'\n';
    cout<<y<<'\n';
   
    auto z= 0.0L;
    std::cout.setf(std::ios_base::fixed, std::ios_base::floatfield);
    cout<<z<<'\n';
    
    
}


//第三章总结练习题
void Chapter3_ClassType::test_in_end()
{
    cout<<6*3/4<<'\n';
    cout<<6.0*3/4<<'\n';
    cout<<15%4<<'\n';
    double i = 3.0;
    double j= 4.1;
    
    cout<<int (i+j)<<'\n';
    //不让这么写，有错误
    //auto crat= U'/U00002155';
    //这个结果是一个double.如果用auto k = 8.25f/2.5定义,k是float类型,aotu会根据结果转化类型.而不是运算过程
    cout<<8.25f/2.5<<'\n';

    //英寸英尺转换
     /*const int change_footToinch=12;//12英寸换算1英尺
    const double change_inchToCm=2.54;//一英寸换算2.54cm
    //cm转成英寸
    int cm=187,foot ,inch;
    cout<<"你的身高:"<<cm/change_inchToCm<<"(英寸)"<<'\n';
    //英寸,转成英寸英尺
    cout<<"输入身高(英寸):";
    cin>>inch;
    foot = inch/change_footToinch;
    inch = inch%change_footToinch;
    cout<<"你的身高为:"<<foot<<"英尺,"<< inch%change_footToinch<<"英寸"<<'\n';*/

    //BMI
    /*const double kgToBang=2.2;
    double kg,mylong,BMI;
    kg = 100;
    mylong= 1.87;
    BMI = kg/(mylong*mylong);
    cout<<"BMI : "<<BMI<<'\n';
    if (BMI>30){cout << "肥胖(肥胖)BMI : "<<BMI<<'\n';}
    else if(BMI>=25 ){cout<<"(超重)BMI : "<<BMI<<'\n';}
    else if (BMI<25 and BMI>=18.5){cout<<"(正常体重)BMI : "<<BMI<<'\n';}
    else if (BMI<18.5){cout<<"(体重不足)BMI : "<<BMI<<'\n';}*/
    //纬度 60进制转化
    /*double du =0 ;
    double fen=0 ;
    double miao=0;
    cout<<"du:";
    cin>>du;
    cout<<"fen:";
    cin>>fen;
    cout<<"miao:";
    cin>>miao;
    double change_du = du+(fen+miao/60)/60;
    cout<<du<<"du,"<<fen<<"fen,"<<miao<<"miao = "<<change_du;*/

    //秒数时间转化小时
    int day,hour,minute,second;
    cout<<"second:";
    second = 316000000;
   // cin>>second;
    cout<<second<<" second = ";
    day=second/24/3600;
    hour = (second % (24 * 3600)) / 3600;
    minute = (second % 3600) / 60;
    //minute = (second-day*24*60-hour*60)%60;
    second = second % 60;
    cout<<day<<"day,"<<hour<<"hour,"<<minute<<"minute,"<<second<<"second."<<'\n';

    //整数运算转化成小数，强制转化一个就可以
    /*
    long long chinaPopulation = 14.1807E8;
    long long allPopulation = 81.8875E8;
    double p=static_cast<double>(chinaPopulation)/allPopulation;
    cout<<"中国人口占全世界:"<<std::fixed<<std::setprecision(5)<<p*100<<"%"<<'\n';
    */

    
}


/*
int  main()
{
    Chapter3_ClassType chapter3;
    cout << "Hello Chapter3!" << '\n';
    //chapter3.tnameType();
    //chapter3.tclimitsType();
    //chapter3.ttest_unsigned_dechexoct();
    //chapter3.ttest_char();
    //chapter3.tuniversalCharacterName();
    //chapter3.ttest_wcha_t();
    //chapter3.ttest_const_double();
    //chapter3.ttest_float();
    //chapter3.ttest_long_double();
    //chapter3.test_castType();
    //chapter3.test_auto();
    chapter3.test_in_end();
    return 0;
}
*/
